﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using YonYou.U8.IN.Forms.StyleToolStrips;
using YonYou.U8.IN.Forms.Win32;

namespace YonYou.U8.IN.Forms
{
    [ToolboxBitmap(typeof(ComboBox))]
    [ToolboxItem(false)]
    public class ComboBoxEx : ComboBox
    {
        public ComboBoxEx()
        {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.BackColor = Color.White;
        }
        #region 属性
        private IntPtr _editHandle;
        private ControlState _buttonState;
        private ControlState _textboxState;
        private Color _baseColor = Color.FromArgb(51, 161, 224);
        private Color _borderColor = ColorTable.ToolStripComboBoxBorderColor;
        private Color _arrowColor = Color.Black;
        private bool _bPainting;
        private SubWindow m_SubWindow;

        [Category("Wade")]
        [DefaultValue(typeof(Color), "51, 161, 224")]
        public Color BaseColor
        {
            get
            {
                return this._baseColor;
            }
            set
            {
                if (this._baseColor != value)
                {
                    this._baseColor = value;
                    base.Invalidate();
                }
            }
        }

        [Category("Wade")]
        [DefaultValue(typeof(Color), "204, 204, 221")]
        [Description("边框颜色")]
        public Color BorderColor
        {
            get
            {
                return this._borderColor;
            }
            set
            {
                if (this._borderColor != value)
                {
                    this._borderColor = value;
                    base.Invalidate();
                }
            }
        }

        [Category("Wade")]
        [DefaultValue(typeof(Color), "19, 88, 128")]
        [Description("箭头颜色")]
        public Color ArrowColor
        {
            get
            {
                return this._arrowColor;
            }
            set
            {
                if (this._arrowColor != value)
                {
                    this._arrowColor = value;
                    base.Invalidate();
                }
            }
        }

        [Category("Wade")]
        [DefaultValue(typeof(Color), "black")]
        [Description("下拉边框颜色")]
        public Color DropDownBorderColor { get; set; }

        [Category("Wade")]
        [DefaultValue(typeof(Color), "white")]
        [Description("下拉框背景颜色")]
        public Color DropDownBackColor { get; set; }

        [Category("Wade")]
        [Description("按钮状态")]
        public ControlState ButtonState
        {
            get
            {
                return this._buttonState;
            }
            set
            {
                if (this._buttonState != value)
                {
                    this._buttonState = value;
                    base.Invalidate(this.ButtonRect);
                }
            }
        }

        [Category("Wade")]
        [Description("文本框状态")]
        public ControlState TextboxState
        {
            get
            {
                return this._textboxState;
            }
            set
            {
                if (this._textboxState != value)
                {
                    this._textboxState = value;
                    base.Invalidate(this.ButtonRect);
                }
            }
        }

        [Category("Wade")]
        [Description("按钮边框长方形")]
        [Browsable(false)]
        public Rectangle ButtonRect
        {
            get
            {
                return this.GetDropDownButtonRect();
            }
        }
        private Rectangle GetDropDownButtonRect()
        {
            return this.GetComboBoxInfo().rcButton.Rect;
        }

        private NativeMethods.ComboBoxInfo GetComboBoxInfo()
        {
            NativeMethods.ComboBoxInfo comboBoxInfo = default;
            comboBoxInfo.cbSize = Marshal.SizeOf(comboBoxInfo);
            NativeMethods.GetComboBoxInfo(this.Handle, ref comboBoxInfo);
            return comboBoxInfo;
        }

        [Browsable(false)]
        public bool ButtonPressed
        {
            get
            {
                return base.IsHandleCreated && this.GetComboBoxButtonPressed();
            }
        }
        private bool GetComboBoxButtonPressed()
        {
            return this.GetComboBoxInfo().stateButton == NativeMethods.ComboBoxButtonState.STATE_SYSTEM_PRESSED;
        }

        [Browsable(false)]
        [Description("文本编辑框句柄")]
        public IntPtr EditHandle
        {
            get
            {
                return this._editHandle;
            }
        }


        [Category("Wade")]
        [Description("文本编辑框区域")]
        [Browsable(false)]
        public Rectangle EditRect
        {
            get
            {
                if (this.DropDownStyle == ComboBoxStyle.DropDownList)
                {
                    Rectangle result = new Rectangle(3, 3, this.Width - this.ButtonRect.Width - 6, base.Height - 6);
                    if (this.RightToLeft == RightToLeft.Yes)
                    {
                        result.X += this.ButtonRect.Right;
                    }
                    return result;
                }
                if (this.IsHandleCreated && this.EditHandle != IntPtr.Zero)
                {
                    RECT  lpRect = default(RECT);
                    GetWindowRect(this.EditHandle, ref lpRect);
                    return this.RectangleToClient(lpRect.Rect);
                }
                return Rectangle.Empty;
            }
        }
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);

        #endregion
        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            this._editHandle = this.GetComboBoxInfo().hwndEdit;
        }
        protected override void OnDropDownClosed(EventArgs e)
        {
            if (this.m_SubWindow != null)
            {
                this.m_SubWindow.ResetIndex();
            }
            base.OnDropDownClosed(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            Point location = e.Location;
            if (this.EditRect.Contains(location))
            {
                this.TextboxState = ControlState.Hover;
                this.ButtonState = ControlState.Normal;
                return;
            }
            if (this.ButtonRect.Contains(location))
            {
                this.TextboxState = ControlState.Hover;
                this.ButtonState = ControlState.Hover;
                return;
            }

        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            Point pt = base.PointToClient(Cursor.Position);
            if (this.EditRect.Contains(pt))
            {
                this.TextboxState = ControlState.Hover;
                this.ButtonState = ControlState.Normal;
                return;
            }
            if (this.ButtonRect.Contains(pt))
            {
                this.ButtonState = ControlState.Hover;
                this.TextboxState = ControlState.Hover;
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            this.ButtonState = ControlState.Normal;
            this.TextboxState = ControlState.Normal;
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            this.ButtonState = ControlState.Normal;
            this.TextboxState = ControlState.Normal;
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 528 && (int)m.WParam == 65536001)
            {
                SubWindow subWindow = new SubWindow();
                subWindow.Owner = this;
                subWindow.AssignHandle(m.LParam);
                this.m_SubWindow = subWindow;
            }
            int msg = m.Msg;
            if (msg == 15)
            {
                this.WmPaint(ref m);
                return;
            }
            base.WndProc(ref m);
        }

        private void WmPaint(ref Message m)
        {
            if (this.DropDownStyle == ComboBoxStyle.Simple)
            {
                base.WndProc(ref m);
                return;
            }
            if (this.DropDownStyle != ComboBoxStyle.DropDown)
            {
                base.WndProc(ref m);
                this.RenderComboBox(ref m);
                return;
            }
            if (!this._bPainting)
            {
                NativeMethods.PAINTSTRUCT paintstruct = default(NativeMethods.PAINTSTRUCT);
                this._bPainting = true;
                NativeMethods.BeginPaint(m.HWnd, ref paintstruct);
                this.RenderComboBox(ref m);
                NativeMethods.EndPaint(m.HWnd, ref paintstruct);
                this._bPainting = false;
                m.Result = NativeMethods.TRUE;
                return;
            }
            base.WndProc(ref m);
        }

        private void RenderComboBox(ref Message m)
        {
            Rectangle rect = new Rectangle(Point.Empty, this.Size);
            Rectangle buttonRect = this.ButtonRect;
            ControlState state = this.ButtonPressed ? ControlState.Pressed : this.ButtonState;
            using (Graphics g = Graphics.FromHwnd(m.HWnd))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                this.RenderComboBoxBackground(g, rect, buttonRect);
                this.RenderConboBoxBorder(g, rect, this.TextboxState);
                this.RenderConboBoxDropDownButton(g, this.ButtonRect, state);
            }
        }

        private void RenderConboBoxBorder(Graphics g, Rectangle rect, ControlState state)
        {
            Color color = this.Enabled ? this._borderColor : SystemColors.ControlDarkDark;
            switch (state)
            {
                case ControlState.Hover:
                    color = Color.FromArgb(239, 203, 148);
                    break;
                default:
                    color = this._borderColor;
                    break;
            }
            using (Pen pen = new Pen(color))
            {
                rect.Width--;
                rect.Height--;
                g.DrawRectangle(pen, rect);
            }
        }

        private void RenderComboBoxBackground(Graphics g, Rectangle rect, Rectangle buttonRect)
        {
            Color color = this.Enabled ? this.BackColor : SystemColors.Control;
            using (SolidBrush solidBrush = new SolidBrush(color))
            {
                buttonRect.Inflate(-1, -1);
                rect.Inflate(-1, -1);
                using (Region region = new Region(rect))
                {
                    region.Exclude(buttonRect);
                    region.Exclude(this.EditRect);
                    g.FillRegion(solidBrush, region);
                }
            }
        }

        /// <summary>
        /// 绘制下拉按钮
        /// </summary>
        /// <param name="g"></param>
        /// <param name="buttonRect"></param>
        /// <param name="state"></param>
        private void RenderConboBoxDropDownButton(Graphics g, Rectangle buttonRect, ControlState state)
        {
            Color borderColor = Color.Empty;
            Color arrowColor = this.Enabled ? this._arrowColor : SystemColors.ControlDarkDark;
            ColorBlend blend = null;
            if (this.Enabled)
            {
                switch (state)
                {
                    case ControlState.Hover:
                        blend = ColorTable.ToolStripButtonSelectedColorBlend;
                        borderColor = ColorTable.ToolStripButtonSelectedBorderColor;
                        break;
                    case ControlState.Pressed:
                        blend = ColorTable.ToolStripButtonPressedColorBlend;
                        borderColor = ColorTable.ToolStripButtonPressedBorderColor;
                        break;
                    default:
                        blend = null;
                        break;
                }
            }
            this.RenderScrollBarArrowInternal(g, buttonRect, blend, borderColor, arrowColor, RoundStyle.None, false, ArrowDirection.Down, LinearGradientMode.Vertical);
        }

        /// <summary>
        /// 绘制箭头下拉图标
        /// </summary>
        /// <param name="g"></param>
        /// <param name="rect"></param>
        /// <param name="blend"></param>
        /// <param name="borderColor"></param>
        /// <param name="arrowColor"></param>
        /// <param name="roundStyle"></param>
        /// <param name="drawBorder"></param>
        /// <param name="arrowDirection"></param>
        /// <param name="mode"></param>
        internal void RenderScrollBarArrowInternal(Graphics g, Rectangle rect, ColorBlend blend, Color borderColor, Color arrowColor, RoundStyle roundStyle, bool drawBorder, ArrowDirection arrowDirection, LinearGradientMode mode)
        {
            if (blend != null)
            {
                rect.Location = new Point(rect.Left + 1, rect.Top - 2);
                rect.Height += 3;
                RenderHelper.RenderBackgroundInternal(g, rect, blend, borderColor, borderColor, roundStyle, 0, drawBorder, mode);
            }
            else
            {
                rect.Inflate(0, -1);
                using (SolidBrush solidBrush = new SolidBrush(this.BackColor))
                {
                    g.FillRectangle(solidBrush, rect);
                }
            }
            using (Brush brush = new SolidBrush(borderColor))
            {
                Pen pen = new Pen(brush);
                GraphicsPath path = GraphicsPathHelper.CreatePath(rect, 2, RoundStyle.None, true);
                g.DrawPath(pen, path);
            }
            using (SolidBrush solidBrush2 = new SolidBrush(arrowColor))
            {
                this.RenderArrowInternal(g, rect, arrowDirection, solidBrush2);
            }
        }

        internal void RenderArrowInternal(Graphics g, Rectangle dropDownRect, ArrowDirection direction, Brush brush)
        {
            Point point = new Point(dropDownRect.Left + dropDownRect.Width / 2, dropDownRect.Top + dropDownRect.Height / 2);
            Point[] points;
            switch (direction)
            {
                case ArrowDirection.Left:
                    points = new Point[]
                    {
                    new Point(point.X + 2, point.Y - 3),
                    new Point(point.X + 2, point.Y + 3),
                    new Point(point.X - 1, point.Y)
                    };
                    break;
                case ArrowDirection.Up:
                    points = new Point[]
                    {
                    new Point(point.X - 3, point.Y + 2),
                    new Point(point.X + 3, point.Y + 2),
                    new Point(point.X, point.Y - 2)
                    };
                    break;
                case ArrowDirection.Right:
                    points = new Point[]
                    {
                        new Point(point.X - 2, point.Y - 3),
                        new Point(point.X - 2, point.Y + 3),
                        new Point(point.X + 1, point.Y)
                    };
                    break;
                default:
                    points = new Point[]
                    {
                        new Point(point.X - 3, point.Y - 1),
                        new Point(point.X + 3, point.Y - 1),
                        new Point(point.X, point.Y+2 )
                    };

                    break;
            }
            g.FillPolygon(brush, points);
        }

    }
}
